#include "bondquotedealchart.h"
#include <widgets/chart/basechart_plot.h>
#include <widgets/chart/basechart_graph.h>
#include <core/comdefs.h>
#include <core/Utility.h>
#include <core/time/system_time.h>
#include <core/StyleMgr.h>
#include <qbtools/tools.h>
#include <widgets/STips.h>
#include <uam/UserAccountManager.h>

#pragma warning(disable:4018)

#define NEW_DETAIL_CFETS_BROKER		    50
#define CHARTBONDQUOTE_MINSHOW 4.f
#define INVALID_PRICE_FLOAT	-0.0001
#define min(a,b)            (((a) < (b)) ? (a) : (b))
#define max(a,b)            (((a) > (b)) ? (a) : (b))

namespace qb
{
	BondQuoteDealChart::BondQuoteDealChart(QWidget* parent)
		: QWidget(parent)
		, m_nBtnSelect(0)
		, m_nMarketType(0)
		, m_nHotPosSize(3)
		, m_nHotPoint(-1)
		, m_nDateSel(0)
		, m_nStartDay(0)
		, m_nEndDay(0)
		, m_nBegin(0)
		, m_nEnd(0)
		, m_nRealBegin(0)
		, m_nRealEnd(0)
		, m_dMinX(0.0)
		, m_dMaxX(0.0)
		, m_dMinY(0.0)
		, m_dMaxY(0.0)
		, m_dOriginMinX(0.0)
		, m_dOriginMaxX(0.0)
		, m_dDragLeft(0.0)
		, m_dDragRight(0.0)
		, m_bShowLine1(true)
		, m_bShowLine2(false)
	{
		memset(&m_szPreClose, 0, sizeof(m_szPreClose));
	}

	BondQuoteDealChart::~BondQuoteDealChart()
	{
	}

	void BondQuoteDealChart::setBondInfo(const CBondInfo* bondinfo)
	{
		mBondInfo = (CBondInfo*)bondinfo;
	}

	void BondQuoteDealChart::loadKLineData(xQBABrokerDealKlineDayList_c* pData)
	{
		inputKLineData(pData);
		if (0 == m_nBtnSelect)
		{
			refreshData();
		}
	}

	void BondQuoteDealChart::loadKLineCloseData(xQBABrokerKlineDayCloseList_Ack* pData)
	{
		inputKLineCloseData(pData);
		if (0 == m_nBtnSelect)
		{
			refreshData();
		}
	}

	void BondQuoteDealChart::loadRealTimeData(xQBMarketStreamList_c* pData)
	{
		inputRealTimeData(pData);
		if (1 == m_nBtnSelect)
		{
			refreshData();
		}
	}

	void BondQuoteDealChart::createChart()
	{
		verticalLayout = new QVBoxLayout(this);
		customPlot = new BaseChartCustomPlot(this);
		customPlot->setOpenGl(true);
		verticalLayout->addWidget(customPlot);
		this->setLayout(verticalLayout);

		connect(customPlot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(onMouseMove(QMouseEvent*)));
		connect(customPlot, &BaseChartCustomPlot::mouseDoubleClick, [=]() { emit mouseDoubleClick(this); });

		QBrush boxBrush(StyleMgr::instance().color("BasicPlate"));
		customPlot->setBackground(boxBrush);
		customPlot->addGraph(customPlot->xAxis, customPlot->yAxis);
		customPlot->xAxis->grid()->setCustomAxisGrid(this);
		customPlot->yAxis->grid()->setCustomAxisGrid(this);
		customPlot->xAxis->setYAxis(customPlot->yAxis);
		customPlot->yAxis->setTickLabelPadding(40);
		customPlot->graph(0)->setPen(QPen(QColor(205, 119, 4), 1.5f));
		customPlot->graph(0)->setLineStyle(BaseChartGraph::lsLine);
		customPlot->graph(0)->setScatterStyle(BaseChartScatterStyle(BaseChartScatterStyle::ssCircle, m_nHotPosSize));
		customPlot->xAxis->setNumberPrecision(4);
		customPlot->xAxis->setCustomGrid();
		customPlot->yAxis->setCustomGrid();
		customPlot->xAxis->setSubTicks(false);
		customPlot->yAxis->setSubTicks(false);
		customPlot->yAxis->ticker()->setTickCount(5);

		QString qText = tr("成交收益率");
		BaseChartTextElement* pte = new BaseChartTextElement(customPlot, qText, QFont("Microsoft YaHei", 9, QFont::Bold));
		pte->setCustomDraw(this);
		pte->setTextFlags(Qt::AlignLeft | Qt::AlignVCenter);
		pte->setTextOffset(18);
		pte->setTextColor(StyleMgr::instance().color("TextNormal"));
		customPlot->plotLayout()->addElement(1, 0, pte);

		bcde = new BaseChartDragBarElement(customPlot);
		customPlot->plotLayout()->addElement(2, 0, bcde);

		refreshData();
	}

	void BondQuoteDealChart::setSelect(int select)
	{
		m_nBtnSelect = select;
	}

	void BondQuoteDealChart::setCalendar(int startDay, int endDay)
	{
		if (isValidCalendar(startDay, endDay))
		{
			m_nStartDay = startDay;
			m_nEndDay = endDay;
		}

		emit calendarChanged(startDay, endDay);
	}

	void BondQuoteDealChart::setMarketType(em_BrokerKinds emCurType)
	{
		if (emCurType == em_Exchange)
			m_nMarketType = 2;
		else if (emCurType == em_CFETS)
			m_nMarketType = 1;
		else
			m_nMarketType = 0;
	}

	void BondQuoteDealChart::setPreClose(const char* pPreClose)
	{
		QB_CHECK_RETURN_VOID1(pPreClose);
		strcpy(m_szPreClose, pPreClose);
	}

	void BondQuoteDealChart::setHotPosSize(int size)
	{
		m_nHotPosSize = size;
	}

	void BondQuoteDealChart::setDateSel(int nIndex)
	{
		m_nDateSel = nIndex;
		m_nStartDay = 0;
		m_nEndDay = 0;
	}

	int BondQuoteDealChart::getDateSel(int nIndex)
	{
		if (m_nBtnSelect != 0)
		{
			return 0;
		}

		PriceKLineList* pDataKLine = GetPriceKLineList();
		if (!pDataKLine || pDataKLine->m_List.size() <= 0) {
			return 0;
		}

		int i = 0;
		switch (nIndex) {
		case 0: {
			std::list<PriceKLine>::reverse_iterator it = pDataKLine->m_List.rbegin();
			UINT date = it->m_Date;
			if ((date % 10000) / 100 > 1) {
				date = date - 100;
			}
			else {
				date = (date / 10000 - 1) * 10000 + 1200 + (date % 100);
			}
			i = pDataKLine->m_List.size() - 1;
			for (; it != pDataKLine->m_List.rend(); it++, i--) {
				if (it->m_Date <= date) {
					i++;
					break;
				}
			}
			break;
		}
		case 1: {
			std::list<PriceKLine>::reverse_iterator it = pDataKLine->m_List.rbegin();
			UINT date = it->m_Date;
			if ((date % 10000) / 100 > 3) {
				date = date - 300;
			}
			else {
				date = (date / 10000 - 1) * 10000 + (((date % 10000) / 100) + 9) * 100 + (date % 100);
			}
			i = pDataKLine->m_List.size() - 1;
			for (; it != pDataKLine->m_List.rend(); it++, i--) {
				if (it->m_Date <= date) {
					i++;
					break;
				}
			}
			break;
		}
		case 2: {
			std::list<PriceKLine>::reverse_iterator it = pDataKLine->m_List.rbegin();
			UINT date = it->m_Date;
			if ((date % 10000) / 100 > 6) {
				date = date - 600;
			}
			else {
				date = (date / 10000 - 1) * 10000 + (((date % 10000) / 100) + 6) * 100 + (date % 100);
			}
			i = pDataKLine->m_List.size() - 1;
			for (; it != pDataKLine->m_List.rend(); it++, i--) {
				if (it->m_Date <= date) {
					i++;
					break;
				}
			}
			break;
		}
		case 3: {
			std::list<PriceKLine>::reverse_iterator it = pDataKLine->m_List.rbegin();
			UINT date = it->m_Date / 10000;
			i = pDataKLine->m_List.size() - 1;
			for (; it != pDataKLine->m_List.rend(); it++, i--) {
				if (date != it->m_Date / 10000) {
					i++;
					break;
				}
			}
			break;
		}
		case 4: {
			std::list<PriceKLine>::reverse_iterator it = pDataKLine->m_List.rbegin();
			UINT date = it->m_Date;
			i = pDataKLine->m_List.size() - 1;
			for (; it != pDataKLine->m_List.rend(); it++, i--) {
				UINT dd = date - it->m_Date;
				if (date - it->m_Date >= 10000) {
					i++;
					break;
				}
			}
			break;
		}
		case 5: {
			break;
		}
		default:
			return 0;
		}

		i = min((int)pDataKLine->m_List.size() - 5, i);
		i = max(0, i);

		return i;
	}

	bool BondQuoteDealChart::getCalendarSel(int& nBegin, int& nEnd)
	{
		if (m_nStartDay == 0 || m_nStartDay >= m_nEndDay)
		{
			return false;
		}

		PriceKLineList* pDataKLine = GetPriceKLineList();
		if (!pDataKLine || pDataKLine->m_List.size() <= 0) {
			return false;
		}

		nBegin = 0;
		int i = 0;
		std::list<PriceKLine>::iterator it;
		for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); it++, i++)
		{
			if (it->m_Date <= m_nStartDay)
				nBegin = i;
			else
				break;
		}

		nEnd = 0;
		i = 0;
		for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); it++, i++) {
			if (it->m_Date > m_nEndDay)
				break;
			nEnd = i;
		}

		nBegin = max(nBegin, 0);
		nEnd = min(nEnd+1, pDataKLine->m_List.size() - 1);

		return true;
	}

	bool BondQuoteDealChart::isValidCalendar(int& nStartDay, int& nEndDay)
	{
		if (nStartDay == 0 || nStartDay >= nEndDay)
		{
			nStartDay = 0;
			nEndDay = 0;
			return false;
		}

		PriceKLineList* pDataKLine = GetPriceKLineList();
		if (!pDataKLine || pDataKLine->m_List.size() <= 0) {
			nStartDay = 0;
			nEndDay = 0;
			return false;
		}

		int nBegin = 0;
		int i = 0;
		std::list<PriceKLine>::iterator it;
		for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); it++, i++)
		{
			if (it->m_Date <= nStartDay)
				nBegin = i;
			else
				break;
		}

		int nEnd = 0;
		i = 0;
		for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); it++, i++) {
			if (it->m_Date > nEndDay)
				break;
			nEnd = i;
		}

		nBegin = max(nBegin, 0);
		nEnd = min(nEnd + 1, pDataKLine->m_List.size() - 1);

		if (nEnd - nBegin <= 5)
		{
			nStartDay = pDataKLine->m_List.front().m_Date;
			nEndDay = pDataKLine->m_List.back().m_Date;
			return false;
		}

		return true;
	}

	void BondQuoteDealChart::setLeftDrag(double ratio)
	{
		QB_CHECK_RETURN_VOID1(customPlot);

		if (m_nBtnSelect == 0)
		{
			PriceKLineList* pDataKLine = GetPriceKLineList();
			if (!pDataKLine || pDataKLine->m_List.size() <= 0) {
				return;
			}

			double dBegin = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nBegin = (int)dBegin;
			m_dDragLeft = max(dBegin, m_dOriginMinX + 0.1);
			m_nBegin = max(nBegin, m_dOriginMinX);
		}
		else
		{
			DealRealTimeList* pRealTime = GetDealRealTimeList();
			if (!pRealTime || pRealTime->m_List.size() <= 0) {
				return;
			}

			double dBegin = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nBegin = (int)dBegin;
			m_dDragLeft = max(dBegin, m_dOriginMinX + 0.1);
			m_nRealBegin = max(nBegin, m_dOriginMinX);
		}
	}

	void BondQuoteDealChart::setRightDrag(double ratio)
	{
		QB_CHECK_RETURN_VOID1(customPlot);

		if (m_nBtnSelect == 0)
		{
			PriceKLineList* pDataKLine = GetPriceKLineList();
			if (!pDataKLine || pDataKLine->m_List.size() <= 0) {
				return;
			}

			double dEnd = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nEnd = (int)dEnd;
			m_dDragRight = min(dEnd, m_dOriginMaxX);
			m_nEnd = min(nEnd + 1, m_dOriginMaxX);
		}
		else
		{
			DealRealTimeList* pRealTime = GetDealRealTimeList();
			if (!pRealTime || pRealTime->m_List.size() <= 0) {
				return;
			}

			double dEnd = ratio * (m_dOriginMaxX - m_dOriginMinX);
			int nEnd = (int)dEnd;
			m_dDragRight = min(dEnd, m_dOriginMaxX);
			m_nRealEnd = min(nEnd + 1, m_dOriginMaxX);

			if (ratio >= 1.0)
			{
				m_nRealEnd = 0;
			}
		}
	}

	void BondQuoteDealChart::setCentralDrag(double ratio1, double ratio2)
	{
		setLeftDrag(ratio1);
		setRightDrag(ratio2);
	}

	PriceKLineList* BondQuoteDealChart::GetPriceKLineList()
	{
		PriceKLineList* pList = &m_DataKLineBroker;
		if (m_nMarketType == 1)pList = &m_DataKLineCFETS;
		else if (m_nMarketType == 2)pList = &m_DataKLineExchange;
		return pList;
	}

	DealRealTimeList* BondQuoteDealChart::GetDealRealTimeList()
	{
		DealRealTimeList* pList = &m_DataDealRealTimeBroker;
		if (m_nMarketType == 1)pList = &m_DataDealRealTimeCFETS;
		else if (m_nMarketType == 2)pList = &m_DataDealRealTimeExchange;
		return pList;
	}

	bool BondQuoteDealChart::drawGridXLines(BaseChartPainter* painter)
	{
		if (m_nBtnSelect == 0)drawGridXLines1(painter);
		else if (m_nBtnSelect == 1)drawGridXLines2(painter);

		return true;
	}

	bool BondQuoteDealChart::drawGridYLines(BaseChartPainter* painter)
	{
		QString szValue;
		QRectF rfText;
		int nTextTop = 10000;//纵轴刻度文字
		int top = customPlot->yAxis->axisRect()->top();
		int bottom = customPlot->yAxis->axisRect()->bottom();
		int tickCount = (customPlot->yAxis->ticker()->tickCount() == 0 ? 5 : customPlot->yAxis->ticker()->tickCount());
		double step = (m_dMaxY - m_dMinY) / tickCount;
		QRectF rect(0, 0, 10000, 10000);
		int nFlag = Qt::TextDontClip | Qt::AlignLeft | Qt::AlignVCenter;
		int i = 0;

		bool isPriceDuplicated = [&](void)->bool {
			if (BondChartTools::GetAccuracyValue() != 2) {
				return false;
			}
			int ii = 0;
			float lastPrice = 0.0f;
			while (1) {
				float price = m_dMinY + step * ii;
				int Y = customPlot->yAxis->coordToPixel(price);
				if (Y<top || Y>bottom)break;
				if (ii > 0 && fabs(price - lastPrice) < 0.01) {
					return true;
				}
				lastPrice = price;
				ii++;
			}
			return false;
		}();

		while (1) {
			float price = m_dMinY + step * i;
			int Y = customPlot->yAxis->coordToPixel(price);
			if (Y < top - 1 || Y > bottom) break;
			if (Y <= bottom)
			{
				painter->drawLine(QLineF(customPlot->xAxis->axisRect()->left() - customPlot->yAxis->tickLabelPadding(), Y, customPlot->xAxis->axisRect()->right(), Y));

				if (BondChartTools::GetAccuracyValue() == 4 || //设置4位精度
					((BondChartTools::GetAccuracyValue() == 2) && isPriceDuplicated)) {//设置2位精度，但有重复数据
					szValue = QString("%1").arg(price, 0, 'f', 4, '0');
				}
				else {
					szValue = QString("%1").arg(price, 0, 'f', 2, '0');
				}

				if (szValue.length() > 0) {
					QRectF measureRect = painter->boundingRect(rect, nFlag, szValue);
					if (nTextTop > Y + measureRect.height()) {
						QPen oldPen = painter->pen();
						painter->setPen(QColor(128, 128, 128, 255));
						painter->drawText(customPlot->xAxis->axisRect()->left() - customPlot->yAxis->tickLabelPadding() + 2, Y - measureRect.height(), measureRect.width(), measureRect.height(), nFlag, szValue);
						painter->setPen(oldPen);
						nTextTop = Y - measureRect.height();
					}
				}
			}
			i++;
			if (i > 100)
				break;
		}

		painter->drawLine(QLineF(customPlot->xAxis->axisRect()->left() - customPlot->yAxis->tickLabelPadding(), top, customPlot->xAxis->axisRect()->right(), top));

		//实时走势图绘制昨收价格线
		if (m_nBtnSelect == 1 && m_nMarketType == 0) {
			if (IsValidPrice(m_szPreClose)) {
				double preClose = atof(m_szPreClose);
				int Y = customPlot->yAxis->coordToPixel(preClose);
				if (Y >= top && Y <= bottom) {

					QPen oldPen = painter->pen();
					QPen pen;
					pen.setStyle(Qt::DotLine);
					pen.setColor(QColor(74, 77, 76, 255));
					painter->setPen(pen);
					painter->drawLine(QLineF(customPlot->xAxis->axisRect()->left() - customPlot->yAxis->tickLabelPadding(), Y, customPlot->xAxis->axisRect()->right(), Y));
					painter->setPen(oldPen);

					int nTipsHeight = 16;
					int nTipsWidth = 38;
					QRect rect(0, 0, 0, 0);
					rect.setTop(Y - nTipsHeight / 2);
					rect.setBottom(rect.top() + nTipsHeight);
					rect.setRight(customPlot->xAxis->axisRect()->left() - 2);
					rect.setLeft(rect.right() - nTipsWidth);
					painter->fillRect(rect, QColor(74, 77, 76, 255));

					QString strTips;
					FormatWholeMktDealPrice(strTips, m_szPreClose);

					QFont oldFont = painter->font();
					oldPen = painter->pen();

					QFont font("Microsoft YaHei");
					font.setPixelSize(10);
					painter->setFont(font);
					painter->setPen(QColor(255, 235, 200, 255));

					painter->drawText(rect.left(), rect.top(), rect.width(), rect.height(), Qt::TextDontClip | Qt::AlignCenter | Qt::AlignVCenter, strTips);
					painter->setPen(oldPen);
					painter->setFont(oldFont);
				}
			}
		}

		return true;
	}

	void BondQuoteDealChart::drawGridXLines1(BaseChartPainter* painter)
	{
		drawMouseMoveLine(painter);

		PriceKLineList* pDataKLine = GetPriceKLineList();

		int count = 0;
		int firstindex = -1, lastindex = -1;
		for (int i = 0; i <= m_dMaxX; i++) {
			if (i >= m_dMinX && i <= m_dMaxX) {
				if (firstindex < 0)firstindex = i;
				lastindex = i;
				count++;
			}
		}
		if (firstindex < 0 || count <= 0)return;
		int dx = max(1, (int)(((float)count) / CHARTBONDQUOTE_MINSHOW + 0.4));
		int top = customPlot->yAxis->axisRect()->top();
		int bottom = customPlot->yAxis->axisRect()->bottom();

		std::list<PriceKLine>::iterator it;
		int n = GetKLineIndex(lastindex, it);
		if (n < 0)return;
		int X, LX;
		QString szText;
		QFont font("Microsoft YaHei");
		font.setPixelSize(12);
		painter->setFont(font);

		if (n == lastindex)
		{
			szText = GetKLineDateString(it);
			X = customPlot->xAxis->coordToPixel(lastindex);
			painter->drawLine(QLineF(X, bottom, X, top));

			int nFlag = Qt::TextDontClip | Qt::AlignCenter | Qt::AlignVCenter;
			QRectF rect(0, 0, 10000, 10000);
			QRectF measureRect = painter->boundingRect(rect, nFlag, szText);
			QPen oldPen = painter->pen();
			painter->setPen(QColor(128, 128, 128, 255));
			LX = min(customPlot->xAxis->axisRect()->right() - measureRect.width(), X - measureRect.width() / 2);
			painter->drawText(LX, bottom, measureRect.width(), measureRect.height(), nFlag, szText);
			painter->setPen(oldPen);
		}
		else
		{
			LX = customPlot->xAxis->axisRect()->right();
		}
		int nXEnd = -1;
		for (n = firstindex; n < lastindex; n += dx)
		{
			if (GetKLineIndex(n, it) != n)continue;
			szText = GetKLineDateString(it);
			X = customPlot->xAxis->coordToPixel(n);
			int nFlag = Qt::TextDontClip | Qt::AlignCenter | Qt::AlignVCenter;
			QRectF rect(0, 0, 10000, 10000);
			QRectF measureRect = painter->boundingRect(rect, nFlag, szText);
			if ((X + measureRect.width() / 2) >= LX)continue;
			if (X < nXEnd) continue;
			nXEnd = X + measureRect.width();
			painter->drawLine(QLineF(X, bottom, X, top));
			int i = 0;

			QPen oldPen = painter->pen();
			painter->setPen(QColor(128, 128, 128, 255));

			for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); it++, i++) {
				if (i == n) {
					szText = strInt2DateInTable(it->m_Date);
					QRectF measureRect = painter->boundingRect(rect, nFlag, szText);
					if (n == lastindex)
						if (X + measureRect.width() / 2 > customPlot->xAxis->axisRect()->right())
							painter->drawText(customPlot->xAxis->axisRect()->right() - measureRect.width(), bottom, measureRect.width(), measureRect.height(), nFlag, szText);
						else
							painter->drawText(X - measureRect.width() / 2, bottom, measureRect.width(), measureRect.height(), nFlag, szText);
					else
						painter->drawText(X - measureRect.width() / 2, bottom, measureRect.width(), measureRect.height(), nFlag, szText);

					break;
				}
			}

			painter->setPen(oldPen);
		}
	}

	void BondQuoteDealChart::drawGridXLines2(BaseChartPainter* painter)
	{
		drawMouseMoveLine(painter);

		int count = 0;
		int firstindex = -1, lastindex = -1;
		for (int i = 0; i <= m_dMaxX; i++) {
			if (i >= m_dMinX && i <= m_dMaxX) {
				if (firstindex < 0)firstindex = i;
				lastindex = i;
				count++;
			}
		}
		if (firstindex < 0 || count <= 0)return;
		int dx = max(1, (int)(((float)count) / CHARTBONDQUOTE_MINSHOW + 0.4));

		int top = customPlot->yAxis->axisRect()->top();
		int bottom = customPlot->yAxis->axisRect()->bottom();

		std::list<DealRealTime>::iterator it;
		int LX = customPlot->xAxis->axisRect()->right(), X;
		QString szText;
		QRectF rfText;
		int nFlag = Qt::TextDontClip | Qt::AlignCenter | Qt::AlignVCenter;
		QRectF rect(0, 0, 10000, 10000);

		if (GetDealRealTimeIndex(lastindex, it)) {
			szText = GetDealRealTimeString(it);
			X = customPlot->xAxis->coordToPixel(lastindex);
			painter->drawLine(QLineF(X, bottom, X, top));

			QRectF measureRect = painter->boundingRect(rect, nFlag, szText);
			QPen oldPen = painter->pen();
			painter->setPen(QColor(128, 128, 128, 255));
			LX =  X - measureRect.width() / 2;
			painter->drawText(LX, bottom, measureRect.width(), measureRect.height(), nFlag, szText);
			painter->setPen(oldPen);
		}

		int nAdjuge = 0;
		for (int n = firstindex; n < lastindex; n += dx) {
			if (!GetDealRealTimeIndex(n, it))continue;
			nAdjuge++;
			if (nAdjuge > 2)break;
		}

		for (int n = firstindex; n < lastindex; n += dx) {
			if (!GetDealRealTimeIndex(n, it))continue;
			szText = GetDealRealTimeString(it);
			X = customPlot->xAxis->coordToPixel(n);
			QRectF measureRect = painter->boundingRect(rect, nFlag, szText);
			if ((X + measureRect.width() / 2) >= LX)continue;

			painter->drawLine(QLineF(X, bottom, X, top));

			QPen oldPen = painter->pen();
			painter->setPen(QColor(128, 128, 128, 255));
			painter->drawText(X - measureRect.width() / 2, bottom, measureRect.width(), measureRect.height(), nFlag, szText);
			painter->setPen(oldPen);
		}
	}

	void BondQuoteDealChart::drawMouseMoveLine(BaseChartPainter* painter)
	{
		QB_CHECK_RETURN_VOID1(customPlot);

		int x = mapFromGlobal(QCursor().pos()).x() - 8;
		int y = mapFromGlobal(QCursor().pos()).y() - 8;
		int top = customPlot->yAxis->axisRect()->top();
		int bottom = customPlot->yAxis->axisRect()->bottom();
		int left = customPlot->yAxis->axisRect()->left();
		int right = customPlot->yAxis->axisRect()->right();

		PriceKLineList* pDataKLine = GetPriceKLineList();
		DealRealTimeList* pRealTime = GetDealRealTimeList();
		if (m_nBtnSelect == 0 && pDataKLine && pDataKLine->m_List.size() > 1 || m_nBtnSelect == 1 && pRealTime && pRealTime->m_List.size() > 1)
		{
			if (m_nBtnSelect == 0)
			{
				right = min((int)customPlot->xAxis->coordToPixel(min((int)m_dMaxX, (int)(pDataKLine->m_List.size()-1))), right);
			}
			else
			{
				right = min((int)customPlot->xAxis->coordToPixel(min((int)m_dMaxX, (int)(pRealTime->m_List.size()-1))), right);
			}
		}
		else
		{
			right = left;
		}

		if (x < left || x > right || y < top || y > bottom)
		{
			return;
		}

		painter->drawLine(QLineF(x, bottom, x, top));
	}

	bool BondQuoteDealChart::customDraw(BaseChartPainter* painter, const QRect& rect)
	{
		painter->fillRect(rect, QColor(38, 55, 53));
		painter->setPen(QColor(205, 119, 4));
		painter->drawLine(QLineF(rect.left() + 6, rect.top() + rect.height() / 2, rect.left() + 14, rect.top() + rect.height() / 2));
		painter->drawLine(QLineF(rect.left() + 6, rect.top() + rect.height() / 2 + 1, rect.left() + 14, rect.top() + rect.height() / 2 + 1));
		return true;
	}

	void BondQuoteDealChart::inputKLineData(xQBABrokerDealKlineDayList_c* pData)
	{
		QB_CHECK_RETURN_VOID1(mBondInfo);

		xQBABrokerDealKlineDayList_c* pKLine = (xQBABrokerDealKlineDayList_c*)pData;
		if (!pKLine)
		{
			m_DataKLineBroker.Clear();
			m_DataKLineCFETS.Clear();
			m_DataKLineExchange.Clear();

			return;
		}

		PriceKLineList* pKLineList = NULL;
		int nMarket = -1;
		if (strcmp(pKLine->m_markettype, "b") == 0) { pKLineList = &m_DataKLineBroker; nMarket = 0; }
		else if (strcmp(pKLine->m_markettype, "50") == 0) { pKLineList = &m_DataKLineCFETS; nMarket = 1; }
		else if (strcmp(pKLine->m_markettype, "e") == 0) { pKLineList = &m_DataKLineExchange; nMarket = 2; }
		if (NULL == pKLineList)return;

		pKLineList->Clear();

		if (pKLine->m_List.size() <= 0)
		{
			return;
		}

		const char* pkey = mBondInfo->GetBondKey();
		const char* plm = mBondInfo->GetListedMarket();

		PriceKLine item;
		std::set<unsigned int> setRepeat;
		for (auto it = pKLine->m_List.begin(); it != pKLine->m_List.end(); ++it)
		{
			if (strcmp(pkey, it->m_bond_key) == 0 && strcmp(plm, it->m_listedmarket) == 0) {
				if (setRepeat.find(it->m_Date) == setRepeat.end()) {
					item.m_Date = it->m_Date;
					item.m_Price1 = it->m_Yield;
					item.m_Price2 = -1000;
					pKLineList->Insert(item);
					setRepeat.insert(item.m_Date);
				}
			}
		}
		pKLineList->m_List.sort();

		if (pKLineList->m_List.size() < 6)
		{
			bcde->setEnable(false);
		}
		else
		{
			bcde->setEnable(true);
		}

		m_dOriginMaxX = max(m_dOriginMaxX, pKLineList->m_List.size() - 1);
		m_dOriginMaxX = min(m_dOriginMaxX, pKLineList->m_List.size() - 1);
		
		if (m_dDragLeft == 0.0 && m_dDragRight == 0.0)
		{
			if (!getCalendarSel(m_nBegin, m_nEnd))
			{
				m_nBegin = getDateSel(m_nDateSel);
			}
		}

		if (m_nBegin > 0 && m_nBegin < pKLineList->m_List.size() - 1)
		{
			auto itBegin = pKLineList->m_List.begin();
			auto itEnd = pKLineList->m_List.begin();
			std::advance(itEnd, m_nBegin);
			pKLineList->m_List.erase(itBegin, itEnd);
		}
		if (m_nEnd - m_nBegin > 0 && m_nEnd - m_nBegin < pKLineList->m_List.size() - 1)
		{
			auto itBegin = pKLineList->m_List.begin();
			auto itEnd = pKLineList->m_List.end();
			std::advance(itBegin, m_nEnd - m_nBegin);
			pKLineList->m_List.erase(itBegin, itEnd);
		}

		if (pKLineList->m_List.size() > 0)
		{
			emit calendarChanged(pKLineList->m_List.front().m_Date, pKLineList->m_List.back().m_Date);
		}
		else
		{
			emit calendarChanged(0, 0);
		}
	}

	void BondQuoteDealChart::inputKLineCloseData(xQBABrokerKlineDayCloseList_Ack* pData)
	{
		QB_CHECK_RETURN_VOID1(mBondInfo);

		xQBABrokerKlineDayCloseList_Ack* pKLine = (xQBABrokerKlineDayCloseList_Ack*)pData;
		if (!pKLine) 
		{
			m_DataKLineBroker.Clear();
			m_DataKLineCFETS.Clear();
			m_DataKLineExchange.Clear();

			return;
		}

		PriceKLineList* pKLineList = NULL;
		int nMarket = -1;
		if (strcmp(pKLine->m_markettype, "b") == 0) { pKLineList = &m_DataKLineBroker; nMarket = 0; }
		else if (strcmp(pKLine->m_markettype, "50") == 0) { pKLineList = &m_DataKLineCFETS; nMarket = 1; }
		else if (strcmp(pKLine->m_markettype, "e") == 0) { pKLineList = &m_DataKLineExchange; nMarket = 2; }
		if (NULL == pKLineList)return;

		pKLineList->Clear();

		if (pKLine->m_List.size() <= 0) 
		{
			return;
		}

		const char* pkey = mBondInfo->GetBondKey();
		const char* plm = mBondInfo->GetListedMarket();

		PriceKLine item;
		std::set<unsigned int> setRepeat;
		for (auto it = pKLine->m_List.begin(); it != pKLine->m_List.end(); ++it) 
		{
			if (strcmp(pkey, it->m_bond_key) == 0 && strcmp(plm, it->m_listed_market) == 0) {
				if (setRepeat.find(it->m_Date) == setRepeat.end()) {
					item.m_Date = it->m_Date;
					item.m_Price1 = it->m_Yield;
					item.m_Price2 = -1000;
					pKLineList->Insert(item);
					setRepeat.insert(item.m_Date);
				}
			}
		}
		pKLineList->m_List.sort();

		if (pKLineList->m_List.size() < 6)
		{
			bcde->setEnable(false);
		}
		else
		{
			bcde->setEnable(true);
		}

		m_dOriginMaxX = max(m_dOriginMaxX, pKLineList->m_List.size() - 1);
		m_dOriginMaxX = min(m_dOriginMaxX, pKLineList->m_List.size() - 1);

		if (m_dDragLeft == 0.0 && m_dDragRight == 0.0)
		{
			if (!getCalendarSel(m_nBegin, m_nEnd))
			{
				m_nBegin = getDateSel(m_nDateSel);
			}
		}

		if (m_nBegin > 0 && m_nBegin < pKLineList->m_List.size() - 1)
		{
			auto itBegin = pKLineList->m_List.begin();
			auto itEnd = pKLineList->m_List.begin();
			std::advance(itEnd, m_nBegin);
			pKLineList->m_List.erase(itBegin, itEnd);
		}
		if (m_nEnd - m_nBegin > 0 && m_nEnd - m_nBegin < pKLineList->m_List.size() - 1)
		{
			auto itBegin = pKLineList->m_List.begin();
			auto itEnd = pKLineList->m_List.end();
			std::advance(itBegin, m_nEnd - m_nBegin);
			pKLineList->m_List.erase(itBegin, itEnd);
		}

		if (pKLineList->m_List.size() > 0)
		{
			emit calendarChanged(pKLineList->m_List.front().m_Date, pKLineList->m_List.back().m_Date);
		}
		else
		{
			emit calendarChanged(0, 0);
		}
	}

	void BondQuoteDealChart::inputRealTimeData(xQBMarketStreamList_c* pData)
	{
		QB_CHECK_RETURN_VOID1(mBondInfo);

		xQBMarketStreamList_c* pRealTime = pData;
		m_DataDealRealTimeBroker.Clear();
		m_DataDealRealTimeCFETS.Clear();
		m_DataDealRealTimeExchange.Clear();
		if ((!pRealTime || pRealTime->m_List.size() <= 0) && m_nBtnSelect != 1)return;

		if (!pRealTime || pRealTime->m_List.size() <= 0) {
			return;
		}

		const char* pkey = mBondInfo->GetBondKey();
		const char* plm = mBondInfo->GetListedMarket();
		bool bConvertible = (strcmp(mBondInfo->GetBondSubType(), "CVB") == 0 || strcmp(mBondInfo->GetBondSubType(), "SCV") == 0);

		std::list<xQBMarketStreamUnit_c>::iterator it;
		DealRealTime item;

		for (it = pRealTime->m_List.begin(); it != pRealTime->m_List.end(); ++it) {
			if (strcmp(it->m_type, "2") == 0 && strcmp(pkey, it->m_body2.m_bondkey) == 0 && strcmp(plm, it->m_body2.m_listedmarket) == 0) {
				DealRealTimeList* pList;

				if (atoi(it->m_company_id) == NEW_DETAIL_CFETS_BROKER)pList = &m_DataDealRealTimeCFETS;
				else if (strcmp(it->m_company_id, "e") == 0)pList = &m_DataDealRealTimeExchange;
				else pList = &m_DataDealRealTimeBroker;

				double price = -1000;
				if (bConvertible && strcmp(it->m_company_id, "e") == 0) {
					if (strlen(it->m_body2.m_cleanPrice) > 0)price = atof(it->m_body2.m_cleanPrice);
				}
				else {
					if (strlen(it->m_body2.m_yield) > 0) {
						price = atof(it->m_body2.m_yield);
						if (price > -0.0001 && price < 0.0001) {
							price = atof(it->m_body2.m_price);
							if (price > 29.9999) price = 0;
						}
					}
				}
				if (price > -999 && price < 999) {
					item.m_time = it->m_modify_time;
					item.m_Price = price;
					int nType = atoi(it->m_operate);
					switch (nType) {
					case 0: FIELDCOPY(item.m_Type, "TKN"); break;
					case 1: FIELDCOPY(item.m_Type, "GVN"); break;
					case 2: FIELDCOPY(item.m_Type, "TRD"); break;
					default:FIELDCOPY(item.m_Type, ""); break;
					}
					if (!VERIRY_IS_CFETST_BROKER_STRING(it->m_company_id) && !VERIRY_IS_EXCHANGE_BROKER_STRING(it->m_company_id)) 
						SSUserAccountManager::instance().GetBrokerNameByID(atoi(it->m_company_id), item.m_Broker, sizeof(item.m_Broker), nullptr);
					else FIELDCOPY(item.m_Broker, "");
					pList->Insert(item);
				}
			}
		}
		m_DataDealRealTimeBroker.m_List.sort();
		m_DataDealRealTimeCFETS.m_List.sort();
		m_DataDealRealTimeExchange.m_List.sort();

		DealRealTimeList* pRealList = GetDealRealTimeList();

		if (pRealList->m_List.size() < 6)
		{
			bcde->setEnable(false);
		}
		else
		{
			bcde->setEnable(true);
		}

		m_dOriginMaxX = max(m_dOriginMaxX, pRealList->m_List.size() - 1);
		m_dOriginMaxX = min(m_dOriginMaxX, pRealList->m_List.size() - 1);
		
		if (m_nRealBegin > 0 && m_nRealBegin < pRealList->m_List.size() - 1)
		{
			auto itBegin = pRealList->m_List.begin();
			auto itEnd = pRealList->m_List.begin();
			std::advance(itEnd, m_nRealBegin);
			pRealList->m_List.erase(itBegin, itEnd);
		}
		if (m_nRealEnd - m_nRealBegin > 0 && m_nRealEnd - m_nRealBegin < pRealList->m_List.size() - 1)
		{
			auto itBegin = pRealList->m_List.begin();
			auto itEnd = pRealList->m_List.end();
			std::advance(itBegin, m_nRealEnd - m_nRealBegin);
			pRealList->m_List.erase(itBegin, itEnd);
		}
	}

	void BondQuoteDealChart::refreshData()
	{
		QB_CHECK_RETURN_VOID1(customPlot && customPlot->graph(0) && bcde);

		PriceKLineList* pDataKLine = GetPriceKLineList();
		DealRealTimeList* pRealTime = GetDealRealTimeList();

		QVector<double>	vctX, vctY;

		m_dMinX = 0;
		m_dMaxX = CHARTBONDQUOTE_MINSHOW;
		if (m_nBtnSelect == 0 && pDataKLine->m_List.size() > 0)
		{
			int i = 0;
			std::list<PriceKLine>::iterator it;
			for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); ++it, i++)
			{
				if ((*it).m_Price1 <= 0)
					continue;

				vctX.push_back(i);
				vctY.push_back((*it).m_Price1);
			}

			m_dMaxX = max(m_dMaxX, pDataKLine->m_List.size() - 1);
		}
		else if (m_nBtnSelect == 1 && pRealTime->m_List.size() > 0)
		{
			int i = 0;
			std::list<DealRealTime>::iterator it;
			for (it = pRealTime->m_List.begin(); it != pRealTime->m_List.end(); ++it, i++)
			{
				vctX.push_back(i);
				vctY.push_back((*it).m_Price);
			}

			m_dMaxX = max(m_dMaxX, pRealTime->m_List.size() - 1);
		}

		customPlot->graph(0)->setData(vctX, vctY);
		GetShowLimit(m_dMinX, m_dMaxX, m_dMinY, m_dMaxY);
		double dExt = (m_dMaxX - m_dMinX) / 20;
		customPlot->yAxis->setRange(m_dMinY, m_dMaxY);
		customPlot->xAxis->setRange(m_dMinX, m_dMaxX + dExt);

		if (m_nBtnSelect == 0 && pDataKLine->m_List.size() > 0 && m_dDragLeft == 0.0 && m_dDragRight == 0.0)
		{
			int end = m_nEnd;
			if (m_nEnd == 0)
			{
				end = m_dOriginMaxX;
			}

			bcde->setPos(getXPos_Value(m_nBegin), getXPos_Value(end));
		}
		else if (m_nBtnSelect == 1 && pRealTime->m_List.size() > 0 && m_dDragLeft == 0.0 && m_dDragRight == 0.0)
		{
			int end = m_nRealEnd;
			if (m_nRealEnd == 0)
			{
				end = m_dOriginMaxX;
			}

			bcde->setPos(getXPos_Value(m_nRealBegin), getXPos_Value(end));
		}

		customPlot->replot(BaseChartCustomPlot::rpQueuedReplot);
	}

	void BondQuoteDealChart::resetData()
	{
		m_dDragLeft = 0.0;
		m_dDragRight = 0.0;
		m_nBegin = 0;
		m_nEnd = 0;
		m_dOriginMinX = 0.0;
		m_dOriginMaxX = 0.0;
	}

	void BondQuoteDealChart::GetShowLimit(double fMinXShow, double fMaxXShow, double& fMinYShow, double& fMaxYShow) 
	{
		if (0 == m_nBtnSelect)
		{
			GetShowLimit1(fMinXShow, fMaxXShow);
		}
		else
		{
			GetShowLimit2(fMinXShow, fMaxXShow);
		}

		if (fabs(fMaxYShow - fMinYShow) < 0.00001f) {
			fMinYShow -= 1;
			fMaxYShow += 1;
		}

		//正常情况5等分，放大后变成10等分
		int nStep =  5;
		double delta = (fMaxYShow - fMinYShow) * 10000 / nStep;
		int nD = (delta < 1.00001) ? 1 : int(delta + 0.99);
		if (nD > 25 && nD % 25 != 0)nD = (nD / 25 + 1) * 25;

		double fMin, fMax;
		int nn = 0;
		while (nn < 2)
		{
			if (nD <= 25)nD = 25;
			else if (nD <= 50)nD = 50;
			else if (nD <= 75)nD = 75;
			else if (nD <= 100)nD = 100;
			else if (nD <= 250)nD = 250;
			else if (nD <= 500)nD = 500;
			else if (nD <= 750)nD = 750;
			else if (nD <= 1000)nD = 1000;
			else if (nD <= 2500)nD = 2500;
			else if (nD <= 5000)nD = 5000;
			else if (nD <= 7500)nD = 7500;
			else if (nD <= 10000)nD = 10000;
			else nD = (nD / 10000 + 1) * 10000;

			delta = nD / 10000.0;
			fMin = (int)((fMinYShow + 0.00001) / delta) * delta;
			fMax = fMin + delta * nStep;
			if (fMax > fMaxYShow)
				break;
			//若上下越界，放宽一格Step
			nD++;
			nn++;
		}

		//居中处理
		int nGap = 1;
		while (fMax - delta * nGap > fMaxYShow)
		{
			nGap++;
		}
		fMaxYShow = fMax - delta * (nGap / 2);
		fMinYShow = fMin - delta * (nGap / 2);
	}

	void BondQuoteDealChart::GetShowLimit1(double fMinXShow, double fMaxXShow)
	{
		PriceKLineList* pDataKLine = GetPriceKLineList();
		if (pDataKLine->m_List.size() <= 0)
		{
			m_dMinY = min_show_def;
			m_dMaxY = max_show_def;
			return;
		}

		m_dMinY = 1000;
		m_dMaxY = -1000;

		bool bBegin = true;
		std::list<PriceKLine>::iterator it;
		std::list<PriceKLine>::iterator itLast1 = pDataKLine->m_List.end();
		std::list<PriceKLine>::iterator itLast2 = pDataKLine->m_List.end();
		int lastitinwork1 = -1;
		int lastitinwork2 = -1;
		int i = 0;
		bool bEnd1 = false;
		bool bEnd2 = false;
		for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); it++, i++) {
			if (i < fMinXShow) {
				if (m_bShowLine1 && it->m_Price1 > 0) {
					itLast1 = it;
					lastitinwork1 = i;
				}
				if (m_bShowLine2 && it->m_Price2 > 0) {
					itLast2 = it;
					lastitinwork2 = i;
				}
			}
			else {
				if (i <= fMaxXShow) {
					if (m_bShowLine1) {
						if (it->m_Price1 > 0) {
							if (itLast1 == pDataKLine->m_List.end()) {//first point
								m_dMinY = min(m_dMinY, it->m_Price1);
								m_dMaxY = max(m_dMaxY, it->m_Price1);
							}
							else {
								if (lastitinwork1 < fMinXShow) {
									double fp = (fMinXShow - lastitinwork1) * (it->m_Price1 - itLast1->m_Price1) / (i - lastitinwork1) + itLast1->m_Price1;
									m_dMinY = min(m_dMinY, fp);
									m_dMaxY = max(m_dMaxY, fp);
								}
								m_dMinY = min(m_dMinY, it->m_Price1);
								m_dMaxY = max(m_dMaxY, it->m_Price1);
							}
							itLast1 = it;
							lastitinwork1 = i;
						}
					}
					if (m_bShowLine2) {
						if (it->m_Price2 > 0) {
							if (itLast2 == pDataKLine->m_List.end()) {//first point
								m_dMinY = min(m_dMinY, it->m_Price2);
								m_dMaxY = max(m_dMaxY, it->m_Price2);
							}
							else {
								if (lastitinwork2 < fMinXShow) {
									double fp = (fMinXShow - lastitinwork2) * (it->m_Price2 - itLast2->m_Price2) / (i - lastitinwork2) + itLast2->m_Price2;
									m_dMinY = min(m_dMinY, fp);
									m_dMaxY = max(m_dMaxY, fp);
								}
								m_dMinY = min(m_dMinY, it->m_Price2);
								m_dMaxY = max(m_dMaxY, it->m_Price2);
							}
							itLast2 = it;
							lastitinwork2 = i;
						}
					}
				}
				else {
					if (m_bShowLine1) {
						if (!bEnd1 && it->m_Price1 > 0) {
							if (itLast1 == pDataKLine->m_List.end()) {
								m_dMinY = min(m_dMinY, it->m_Price1);
								m_dMaxY = max(m_dMaxY, it->m_Price1);
							}
							else {
								if (lastitinwork1 < fMinXShow) {
									double fp = (it->m_Price1 - itLast1->m_Price1) * (fMinXShow - lastitinwork1) / (i - lastitinwork1) + itLast1->m_Price1;
									m_dMinY = min(m_dMinY, fp);
									m_dMaxY = max(m_dMaxY, fp);
								}
								double fp = (it->m_Price1 - itLast1->m_Price1) * (fMaxXShow - lastitinwork1) / (i - lastitinwork1) + itLast1->m_Price1;
								m_dMinY = min(m_dMinY, fp);
								m_dMaxY = max(m_dMaxY, fp);
							}
							bEnd1 = true;
						}
					}
					else bEnd1 = true;
					if (m_bShowLine2) {
						if (!bEnd2 && it->m_Price2 > 0) {
							if (itLast2 == pDataKLine->m_List.end()) {
								m_dMinY = min(m_dMinY, it->m_Price1);
								m_dMaxY = max(m_dMaxY, it->m_Price1);
							}
							else {
								if (lastitinwork2 < fMinXShow) {
									double fp = (it->m_Price2 - itLast2->m_Price2) * (fMinXShow - lastitinwork2) / (i - lastitinwork2) + itLast2->m_Price2;
									m_dMinY = min(m_dMinY, fp);
									m_dMaxY = max(m_dMaxY, fp);
								}
								double fp = (it->m_Price2 - itLast2->m_Price2) * (fMaxXShow - lastitinwork2) / (i - lastitinwork2) + itLast2->m_Price2;
								m_dMinY = min(m_dMinY, fp);
								m_dMaxY = max(m_dMaxY, fp);
							}
							bEnd2 = true;
						}
					}
					else bEnd2 = true;
					if (bEnd1 && bEnd2)break;
				}
			}
		}
	}

	void BondQuoteDealChart::GetShowLimit2(double fMinXShow, double fMaxXShow)
	{
		DealRealTimeList* pRealTime = GetDealRealTimeList();
		if (pRealTime->m_List.size() <= 0) {
			m_dMinY = min_show_def;
			m_dMaxY = max_show_def;
			return;
		}

		m_dMinY = 1000;
		m_dMaxY = -1000;

		bool bBegin = true;
		std::list<DealRealTime>::iterator it;
		std::list<DealRealTime>::iterator itLast = pRealTime->m_List.end();
		int lastitinwork = -1;
		int i = 0;
		bool bEnd = false;
		for (it = pRealTime->m_List.begin(); it != pRealTime->m_List.end(); ++it, i++) {
			if (i < fMinXShow) {
				if (it->m_Price > -999) {
					itLast = it;
					lastitinwork = i;
				}
			}
			else {
				if (i <= fMaxXShow) {
					if (it->m_Price > -999) {
						if (itLast == pRealTime->m_List.end()) {//first point
							m_dMinY = min(m_dMinY, it->m_Price);
							m_dMaxY = max(m_dMaxY, it->m_Price);
						}
						else {
							if (lastitinwork < fMinXShow) {
								double fp = it->m_Price - (it->m_Price - itLast->m_Price) * (i - fMinXShow);
								m_dMinY = min(m_dMinY, fp);
								m_dMaxY = max(m_dMaxY, fp);
							}
							m_dMinY = min(m_dMinY, it->m_Price);
							m_dMaxY = max(m_dMaxY, it->m_Price);
						}
						itLast = it;
						lastitinwork = i;
					}
				}
				else {
					if (!bEnd && it->m_Price > -999) {
						if (itLast == pRealTime->m_List.end()) {
							m_dMinY = min(m_dMinY, it->m_Price);
							m_dMaxY = max(m_dMaxY, it->m_Price);
						}
						else {
							if (lastitinwork < fMinXShow) {
								double fp = (it->m_Price - itLast->m_Price) * (fMinXShow - lastitinwork) / (i - lastitinwork) + itLast->m_Price;
								m_dMinY = min(m_dMinY, fp);
								m_dMaxY = max(m_dMaxY, fp);
							}
							double fp = (it->m_Price - itLast->m_Price) * (fMaxXShow - lastitinwork) / (i - lastitinwork) + itLast->m_Price;
							m_dMinY = min(m_dMinY, fp);
							m_dMaxY = max(m_dMaxY, fp);
						}
						bEnd = true;
						break;
					}
				}
			}
		}

		if (IsValidPrice(m_szPreClose)) {
			double preClose = atof(m_szPreClose);
			if (m_dMaxY > m_dMinY && m_dMinY > preClose) {//最大值>最小值>昨收价
				m_dMinY = floor(preClose / 0.0025) * 0.0025; //向下取整
			}
			if (preClose > m_dMaxY && m_dMaxY > m_dMinY) {//昨收价>最大值>最小值
				m_dMaxY = floor(preClose / 0.0025) * 0.0025; //向下取整
			}
		}
	}

	int BondQuoteDealChart::GetKLineIndex(int nIndex, std::list<PriceKLine>::iterator& it) {
		PriceKLineList* pDataKLine = GetPriceKLineList();
		int i = 0;
		std::list<PriceKLine>::iterator itTemp = pDataKLine->m_List.end();
		for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); it++, i++) {
			if (i == nIndex) {
				return i;
			}
			itTemp = it;
		}
		if (it == pDataKLine->m_List.end() && itTemp != pDataKLine->m_List.end()) {
			it = itTemp;
			return pDataKLine->m_List.size() - 1;
		}
		return -1;
	}

	QString	BondQuoteDealChart::GetKLineDateString(std::list<PriceKLine>::iterator& it)
	{
		PriceKLineList* pDataKLine = GetPriceKLineList();
		QString szText;
		if (it != pDataKLine->m_List.end()) {
			szText = strInt2DateInTable(it->m_Date);
		}
		return szText;
	}

	QString	BondQuoteDealChart::strInt2DateInTable(UINT nDate)
	{
		return QString::asprintf("%04d-%02d-%02d", nDate / 10000, (nDate % 10000) / 100, nDate % 100);
	}

	bool BondQuoteDealChart::IsValidPrice(const char* price) const {
		return (strlen(price) > 0 && IsValidPrice(atof(price)));
	}

	bool BondQuoteDealChart::IsValidPrice(double price) const {
		return (price > INVALID_PRICE_FLOAT);
	}

	void BondQuoteDealChart::FormatWholeMktDealPrice(QString& strPrice, const char* cParam)
	{
		strPrice = "--";
		if (strlen(cParam) > 0) {
			strPrice = QString("%1").arg(SSTools::PriceRemoveZero(cParam, 2).c_str());
			if (strPrice.isEmpty()) strPrice = "--";
		}
	}

	bool BondQuoteDealChart::GetDealRealTimeIndex(int nIndex, std::list<DealRealTime>::iterator& it) {
		DealRealTimeList* pRealTime = GetDealRealTimeList();
		int i = 0;
		for (it = pRealTime->m_List.begin(); it != pRealTime->m_List.end(); it++, i++) {
			if (i == nIndex) {
				return true;
			}
		}
		return false;
	}

	QString	BondQuoteDealChart::GetDealRealTimeString(std::list<DealRealTime>::iterator& it) {
		DealRealTimeList* pRealTime = GetDealRealTimeList();
		QString szText;
		if (it != pRealTime->m_List.end()) {
			qb::base::CTime T(it->m_time);
			szText = QString::asprintf("%02d:%02d", T.GetHour(), T.GetMinute());
		}
		return szText;
	}

	void BondQuoteDealChart::paintEvent(QPaintEvent* event)
	{
		QStylePainter painter(this);

		painter.fillRect(rect(), StyleMgr::instance().color("BasicPlate"));
	}

	void BondQuoteDealChart::leaveEvent(QEvent* event)
	{
		QB_CHECK_RETURN_VOID1(customPlot);

		customPlot->replot();
	}

	QString BondQuoteDealChart::strChartWeekDay(int i) {
		switch (i) {
		case 0: {return tr("星期日"); break; }
		case 1: {return tr("星期一"); break; }
		case 2: {return tr("星期二"); break; }
		case 3: {return tr("星期三"); break; }
		case 4: {return tr("星期四"); break; }
		case 5: {return tr("星期五"); break; }
		case 6: {return tr("星期六"); break; }
		default:break;
		}
		return "";
	}

	double BondQuoteDealChart::getXPos_Value(double value)
	{
		QB_CHECK_RETURN_VALUE(bcde, 0);

		if (m_dOriginMaxX - m_dOriginMinX == 0) return 0;
		return (value - m_dOriginMinX) / (m_dOriginMaxX - m_dOriginMinX) * bcde->rect().width();
	}

	void BondQuoteDealChart::onMouseMove(QMouseEvent* event)
	{
		QB_CHECK_RETURN_VOID1(customPlot && customPlot->graph(0));

		double dm = customPlot->graph(0)->selectTest(event->pos(), false);
		if (0 < dm && 2 > dm)
		{
			QPen pen(QColor(225, 146, 0));
			pen.setWidth(2);
			customPlot->graph(0)->setPen(pen);
		}
		else
		{
			QPen pen(QColor(205, 119, 4));
			pen.setWidth(1);
			customPlot->graph(0)->setPen(pen);
		}

		customPlot->replot();

		if (m_nBtnSelect == 0)
		{
			std::list<PriceKLine>::iterator it;
			PriceKLineList* pDataKLine = GetPriceKLineList();
			int i = 0;
			for (it = pDataKLine->m_List.begin(); it != pDataKLine->m_List.end(); ++it, i++) 
			{
				int X = customPlot->xAxis->coordToPixel(i);
				if (abs(event->pos().x() - X) < 3) {
					if (m_nHotPoint != i) {
						m_nHotPoint = i;
					}
					
					QString szTip;
					qb::base::CTime T(it->m_Date / 10000, (it->m_Date % 10000) / 100, it->m_Date % 100, 8, 0, 0);
					szTip = QString("%1-%2-%3 %4").arg(T.GetYear()).arg(T.GetMonth(), 2, 10, QLatin1Char('0')).arg(T.GetDay(), 2, 10, QLatin1Char('0')).arg(strChartWeekDay(T.GetDayOfWeek() - 1));

					if (it->m_Price1 > -999) {
						std::vector<QBTipCustomItem> vctCustomItem;
						QBTipCustomItem item;
						item.row = 1;
						item.col = 1;
						item.clrNormal = QColor(223, 174, 76, 255);
						vctCustomItem.push_back(item);

						QString qText = tr("\n成交收益率");
						QString szPrice = QString(" %1").arg(it->m_Price1, 0, 'f', 4, '0');
						szTip.append(qText);
						szTip.append(szPrice);
						QBTips::showText(event->screenPos().toPoint(), szTip, this, &vctCustomItem);
					}
					else {
						QBTips::showText(event->screenPos().toPoint(), szTip, this);
					}
					
					return;
				}
			}
		}
		else if (m_nBtnSelect == 1)
		{
			DealRealTimeList* pRealTime = GetDealRealTimeList();
			std::list<DealRealTime>::iterator it;
			int i = 0;
			for (it = pRealTime->m_List.begin(); it != pRealTime->m_List.end(); ++it, i++) {
				int X = customPlot->xAxis->coordToPixel(i);
				if (abs(event->pos().x() - X) < 3) {
					if (m_nHotPoint != i) {
						m_nHotPoint = i;
					}

					QString szTip;
					qb::base::CTime T(it->m_time);
					char szTime[128];
					sprintf(szTime, "%d-%02d-%02d %02d:%02d:%02d", T.GetYear(), T.GetMonth(), T.GetDay(), T.GetHour(), T.GetMinute(), T.GetSecond());
					szTip.append(szTime);
					if (it->m_Price > -999) {
						std::vector<QBTipCustomItem> vctCustomItem;
						QBTipCustomItem item;
						item.row = 1;
						item.col = 1;
						item.clrNormal = QColor(223, 174, 76, 255);
						vctCustomItem.push_back(item);

						QString szPrice = QString("%1 %2").arg(it->m_Type).arg(it->m_Price, 0, 'f', 4, '0');
						szTip.append("\n");
						szTip.append(szPrice);
						QBTips::showText(event->screenPos().toPoint(), szTip, this, &vctCustomItem);
					}
					else {
						QBTips::showText(event->screenPos().toPoint(), szTip, this);
					}

					return;
				}
			}
		}

		if (m_nHotPoint >= 0) {
			m_nHotPoint = -1;
			QBTips::hideTip();
		}
	}
}
